#include "ItemModel.h"
#include "ItemGroup.h"
#include "Item.h"
//#include "ItemReference.h"
#include "Defines.h"



ItemModel::ItemModel(QObject* parent)
    : QAbstractItemModel(parent)
{
}



ItemModel::ItemModel(ItemGroup *root, QObject *parent)
    : QAbstractItemModel(parent)
{
    m_root = root;
}



ItemModel::~ItemModel()
{
    if (!m_root.isNull() && !m_root->parent()) m_root->deleteLater();
}



ItemGroup* ItemModel::rootItem() const
{
    return m_root.data();
}



QModelIndex ItemModel::index(int row, int column, const QModelIndex &parent) const
{
    if (m_root.isNull() || !hasIndex(row, column, parent)) return QModelIndex();

    AbstractItem* parentItem = 0;
    if (!parent.isValid())
    {
        parentItem = m_root.data();
    }
    else
    {
        QObject* obj = static_cast<QObject*>(parent.internalPointer());
        parentItem = dynamic_cast<AbstractItem*>(obj);
    }

    if (!parentItem || parentItem->itemCount() <= row)
    {
        return QModelIndex();
    }


    AbstractItem* item = parentItem->itemAt(row);
    if (!item) return QModelIndex();

    return createIndex(row, column, item);
}



QModelIndex ItemModel::parent(const QModelIndex &child) const
{
    if (m_root.isNull() || !child.isValid()) return QModelIndex();

    QObject* childObj = static_cast<QObject*>(child.internalPointer());
    AbstractItem* childItem = dynamic_cast<AbstractItem*>(childObj);
    if (!childItem) return QModelIndex();

    AbstractItem* item = qobject_cast<AbstractItem*>(childItem->parent());
    if (!item || item == m_root.data()) return QModelIndex();

    int row = item->children().indexOf(childItem);
    return createIndex(row, 0, item);
}



int ItemModel::rowCount(const QModelIndex &parent) const
{
    if (m_root.isNull()) return 0;

    ItemGroup* group = 0;
    if (!parent.isValid())
    {
        group = m_root.data();
    }
    else
    {
        QObject* obj = static_cast<QObject*>(parent.internalPointer());
        group = dynamic_cast<ItemGroup*>(obj);
    }

    if (!group) return 0;

    return group->itemCount();
}



int ItemModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_root->fieldCount();
}



QVariant ItemModel::data(const QModelIndex &index, int role) const
{
    if (m_root.isNull() || !index.isValid() || role != Qt::DisplayRole) return QVariant();

    QObject* obj = static_cast<QObject*>(index.internalPointer());
    AbstractItem* item = dynamic_cast<AbstractItem*>(obj);

    if (!item) return QVariant();

    if (index.column() == Item::ValueData)
    {
        return item->data(index.column());
    }
    return item->data(index.column());
}



bool ItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid() || role != Qt::EditRole) return false;

    QObject* obj = static_cast<QObject*>(index.internalPointer());
    AbstractItem* item = dynamic_cast<AbstractItem*>(obj);
    if (!item) return false;

    int data_type = index.column();
    item->setData(data_type, value);

    emit dataChanged(index,index);
    return true;
}



QVariant ItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    Q_UNUSED(orientation);

    if (role != Qt::DisplayRole) return QVariant();

    if (section < 0 || section >= m_root->fieldCount()) return QVariant();

    // todo: all data type names to common defines.
    switch (section)
    {
    case AbstractItem::IdData: return tr("Id");
    case AbstractItem::NameData: return tr("Name");
    case AbstractItem::DescData: return tr("Description");
    case AbstractItem::CategoryData: return tr("Category");

    case Item::ValueData: return tr("Value");
    default: return tr("Unknown Field");
    }
}



Qt::ItemFlags ItemModel::flags(const QModelIndex &index) const
{
    if (index.column() == AbstractItem::CategoryData) return QAbstractItemModel::flags(index);

    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}



bool ItemModel::insertRow(int row, const QModelIndex &parent)
{
    if (m_root.isNull())
    {
        return false;
    }

    beginInsertRows(parent, row, row);
    if (!parent.isValid())
    {
        (void) new ItemGroup(tr("New Item Group"), m_root.data());
        endInsertRows();
        emit layoutChanged();
        return true;
    }

    QObject* parentObj = static_cast<QObject*>(parent.internalPointer());
    AbstractItem* parentItem = dynamic_cast<AbstractItem*>(parentObj);
    if (!parentItem)
    {
        endInsertRows();
        return false;
    }

    switch (parentItem->category())
    {
    case ItemCategory_Group:
        (void) new Item(tr("New Item"), parentItem);
        break;
//    case ItemCategory_Item:
//        qDebug("Created reference item");
//        (void) new ItemReference(parentItem);
//        break;
    default:
        endInsertRows();
        return false;
    }

    endInsertRows();
    emit layoutChanged();
    return true;
}



